#! coding:utf-8

import pickle as pkl
import os

from web.app.represent_feature import VectorGeneration
from web.app.util import parse_inquiry

current_path = r'/home/ubuntu/data/web/app'


class MedicalRecordRetrieval(object):
    def __init__(self, search_model='model/search_model.pkl',
                 data_model='model/retrieval_origin.pkl',
                 pca_model='model/pca.pkl',
                 topk=10):
        if search_model is None or not os.path.isfile(search_model):
            search_model = os.path.join(current_path, 'model/search_model.pkl')
        with open(search_model, 'rb') as f:
            self._search_model = pkl.load(f)
        if data_model is None or not os.path.isfile(data_model):
            data_model = os.path.join(current_path, 'model/retrieval_origin.pkl')
        with open(data_model, 'rb') as f:
            self._data_model = pkl.load(f)
        if pca_model is None or not os.path.isfile(pca_model):
            pca_model = os.path.join(current_path, 'model/pca.pkl')
        with open(pca_model, 'rb') as f:
            self._pca = pkl.load(f)
        self._topk = topk
        self._vec_gen = VectorGeneration()

    def get_list_user(self):
        return  self._data_model

    def get_topk_similar(self, retrieval_vector):
        retrieval_vec = self._pca.transform([retrieval_vector])
        dist, ind = self._search_model.query(retrieval_vec, k=self._topk)
        # print(dist[0])
        # print(ind[0])
        res = []
        for i, idx in enumerate(ind[0]):
            res.append((idx, dist[0][i]))
        res = sorted(res, key=lambda data: data[1])
        # print(res)
        mr_res = []
        for idx, _ in res:
            # print(idx)
            # print(self._data_model[idx])
            mr_res.append(self._data_model[idx])
        return mr_res

    def get_topk_similar_with_score(self, user_info, report, inquiry, tongue_feature, sim_data):
        res_data = []
        items = user_info.split(' ')
        import numpy as np
        if len(items) < 3:
            info_vec = np.zeros(12)
        else:
            age, weight, height = float(items[0]), float(items[1]), float(items[2])
            info_vec = self._vec_gen.represent_user_info(age, weight, height)
        report_vec = self._vec_gen.represent_report(report)
        inquiry_vec = self._vec_gen.represent_inquiry(parse_inquiry(inquiry))
        tongue_vec = self._vec_gen.represent_tongue(tongue_feature)

        for  data in sim_data:
            temp_dic = {}
            score = 0.

            temp_dic['patient_information'] = data['patient_information']
            temp_dic['condition_report'] = data['condition_report']
            temp_dic['inquiry_sheet'] = data['inquiry_sheet']
            temp_dic['tongue_url'] = data['tongue_url']
            temp_dic['tongue_vector'] = data['tongue_vector']
            items = data['patient_information'].split(' ')
            age, weight, height = float(items[0]), float(items[1]), float(items[2])
            tui_vec = self._vec_gen.represent_user_info(age, weight, height)
            score_info = self._cal_cosine(info_vec, tui_vec)
            temp_dic['score_patient_information'] = score_info
            score += 0.1*score_info
            tr_vec = self._vec_gen.represent_report(data['condition_report'])
            score_report = self._cal_cosine(report_vec, tr_vec)
            score += 0.1 * score_report
            temp_dic['score_condition_report'] = self._cal_cosine(report_vec, tr_vec)
            ti_vec = self._vec_gen.represent_inquiry(parse_inquiry(data['inquiry_sheet'].replace('\r\n', '@@')))
            score_vec = self._cal_cosine(inquiry_vec, ti_vec)
            score += 0.5 * score_vec
            temp_dic['score_inquiry_sheet'] = self._cal_cosine(inquiry_vec, ti_vec)
            tf_list = data['tongue_vector'].strip('[]').split(',')
            tt_vec = self._vec_gen.represent_tongue(tf_list)
            score_tongue_vec = self._cal_cosine(tongue_vec, tt_vec)
            score += 0.3 * score_tongue_vec
            temp_dic['score_tongue_vector'] = self._cal_cosine(tongue_vec, tt_vec)
            res_data.append((temp_dic,'%.2f'%score))
        res_data = sorted(res_data,key = lambda key : key[1] ,reverse=True )
        index = 0

        tongue_map = r'/home/ubuntu/data/web/app/dictionary/tongue_mapping.txt'
        map_tongue = open(tongue_map, encoding='UTF-8-sig').readlines()
        dict_tongue = {}
        for line in map_tongue:
            slip = line.strip('\n').split('\t')
            dict_tongue[slip[0]] = slip[-1]

        data_similar = []
        normal_tongue_list = ['0-3','1-0','2-0','3-3','4-3','5-0','6-0','7-0','8-0','9-0','10-0','10-1','11-3','12-3','13-0','14-0']
        for dic, sum_score in res_data:
            index += 1
            tongue_map_string = ''
            if dic['tongue_vector'] != 'NULL':
                for i in range(len(dic['tongue_vector'][1:-1])//2+1):
                    keym = str(i) + '-' + dic['tongue_vector'][1:-1][2*i]
                    if keym not in normal_tongue_list:
                        tongue_map_string += dict_tongue[keym] + ','
            else:
                tongue_map_string = 'NULL'

            dic['index'] = index
            dic['sum_score'] = sum_score
            dic['tongue_map'] = tongue_map_string
            data_similar.append(dic)
        return data_similar


    def _cal_cosine(self, vec1, vec2):
        cross_sum = 0.0
        sum1 = 0.0
        sum2 = 0.0
        for idx, val in enumerate(vec1):
            cross_sum += val * vec2[idx]
            sum1 += val * val
            sum2 += vec2[idx] * vec2[idx]
        if sum1 == 0.0 or sum2 == 0.0:
            return 0.0
        return round(cross_sum / (sum1 ** 0.5) / (sum2 ** 0.5),2)

